/*
   Local echolalia server. Listens for messages from bashrecord.
*/
package main

import (
	"echolalia"
	"encoding/json"
	"flag"
	"log"
	"net"
	"net/http"
	"net/rpc"
	"strings"
)

// TODO: a unix domain socket is a better choice than a tcp socket for the
// local service -- that way, multiple users can run a service on the same
// machine without having to worry about conflicting over the well-known port.
var addr = flag.String("addr", "localhost:11121", "echolalia local service address")
var remoteAddr = flag.String("remote", "http://localhost:8080/api/listen",
	"echolalia remote service address")

type LocalProtocol struct {
	Forwarder chan *echolalia.Command
}

// Pull commands from the buffer and upload them.
func Handoff(fwd chan *echolalia.Command) {
	for cmd := range fwd {
		buf, err := json.Marshal(map[string]interface{}{
			"cmd":      cmd.Cmd,
			"pwd":      cmd.Pwd,
			"ppid":     cmd.Ppid,
			"ts":       cmd.Timestamp.UTC(),
			"username": cmd.User.Username,
			"hostname": cmd.Hostname,
		})
		if err != nil {
			log.Printf("json.Marshal: %v\n", err)
			continue
		}

		jsonBody := strings.NewReader(string(buf))
		resp, err := http.Post(*remoteAddr, "application/json", jsonBody)
		if err != nil {
			log.Printf("http.Post: %v\n", err)
			continue
		}
		defer resp.Body.Close()
	}
}

func (t *LocalProtocol) RecordCommand(args *echolalia.Command, reply *int) error {
	select {
	case t.Forwarder <- args:
	default:
		// The other goroutine is having trouble uploading commands.
		// Drop them rather than blocking.
		log.Printf("Buffer full, dropping command")
	}
	*reply = 0
	return nil
}

func main() {
	fwd := make(chan *echolalia.Command, 100)
	go Handoff(fwd)

	rpc.Register(&LocalProtocol{fwd})
	rpc.HandleHTTP()
	listener, err := net.Listen("tcp", *addr)
	if err != nil {
		log.Fatal(err)
	}
	http.Serve(listener, nil)
}
